/*********************************************************************
 *          (C) COPYRIGHT TEXAS INSTRUMENTS, INC. 2000-2002
 * FlashBurn Programming Functions
 *     for DM642 EVM
 */

/*
 */

#include <stdio.h>
#include "type.h"
#include "c642evm.h"
#include "FBTC642.h"
#include "FBCmd.h"

	/* Local prototype
	 */
static GetFlashBuf(u8 *dest, u8 *flashsrc, u16 nBytes);

	/* Used by the checksum calc functions
	 */
static volatile unsigned long cksum = 0;

    /* flashstart/next are used to track
     * where we are in a "flat" Flash memory.
     * Paging, etc. are handled by helper
     * funcs.
     */  
static volatile u8 *flashstart = (volatile u8 *)FLASH_START;
static volatile u8 *flashnext  = (volatile u8 *)FLASH_START;

	/* These are "override" values, in case the
	 * Host has sent new flash base addr and size.
     * flashbaseov is 0xffffffff normally, but changes
     * if Host sends the Change FLASHSTART Address command.
     * Thus if it's not 0xffffffff, then it should be used
     * instead of the FLASH_START value. 
	 */
static volatile u8 *flashbaseov = (u8 *)0xffffffffUL;
static unsigned long flashsizeov =  0xffffffffUL;

/* Constant table containing end address of each sector */
unsigned long sector_end[FLASH_SECTORS] = {
    FLASH_START + 0x00ffff, /* Sector 0  */
    FLASH_START + 0x01ffff, /* Sector 1  */
    FLASH_START + 0x02ffff, /* Sector 2  */
    FLASH_START + 0x03ffff, /* Sector 3  */
    FLASH_START + 0x04ffff, /* Sector 4  */
    FLASH_START + 0x05ffff, /* Sector 5  */
    FLASH_START + 0x06ffff, /* Sector 6  */
    FLASH_START + 0x07ffff, /* Sector 7  */    
    FLASH_START + 0x08ffff, /* Sector 8  */
    FLASH_START + 0x09ffff, /* Sector 9  */
    FLASH_START + 0x0affff, /* Sector 10 */
    FLASH_START + 0x0bffff, /* Sector 11 */
    FLASH_START + 0x0cffff, /* Sector 12 */
    FLASH_START + 0x0dffff, /* Sector 13 */
    FLASH_START + 0x0effff, /* Sector 14 */
    FLASH_START + 0x0fffff, /* Sector 15 */
    FLASH_START + 0x10ffff, /* Sector 16 */
    FLASH_START + 0x11ffff, /* Sector 17 */
    FLASH_START + 0x12ffff, /* Sector 18 */
    FLASH_START + 0x13ffff, /* Sector 19 */
    FLASH_START + 0x14ffff, /* Sector 20 */
    FLASH_START + 0x15ffff, /* Sector 21 */
    FLASH_START + 0x16ffff, /* Sector 22 */
    FLASH_START + 0x17ffff, /* Sector 23 */
    FLASH_START + 0x18ffff, /* Sector 24 */
    FLASH_START + 0x19ffff, /* Sector 25 */
    FLASH_START + 0x1affff, /* Sector 26 */
    FLASH_START + 0x1bffff, /* Sector 27 */
    FLASH_START + 0x1cffff, /* Sector 28 */
    FLASH_START + 0x1dffff, /* Sector 29 */
    FLASH_START + 0x1effff, /* Sector 30 */
    FLASH_START + 0x1fffff, /* Sector 31 */
    FLASH_START + 0x20ffff, /* Sector 32 */
    FLASH_START + 0x21ffff, /* Sector 33 */
    FLASH_START + 0x22ffff, /* Sector 34 */
    FLASH_START + 0x23ffff, /* Sector 35 */
    FLASH_START + 0x24ffff, /* Sector 36 */
    FLASH_START + 0x25ffff, /* Sector 37 */
    FLASH_START + 0x26ffff, /* Sector 38 */
    FLASH_START + 0x27ffff, /* Sector 39 */    
    FLASH_START + 0x28ffff, /* Sector 40 */
    FLASH_START + 0x29ffff, /* Sector 41 */
    FLASH_START + 0x2affff, /* Sector 42 */
    FLASH_START + 0x2bffff, /* Sector 43 */
    FLASH_START + 0x2cffff, /* Sector 44 */
    FLASH_START + 0x2dffff, /* Sector 45 */
    FLASH_START + 0x2effff, /* Sector 46 */
    FLASH_START + 0x2fffff, /* Sector 47 */
    FLASH_START + 0x30ffff, /* Sector 48 */
    FLASH_START + 0x31ffff, /* Sector 49 */
    FLASH_START + 0x32ffff, /* Sector 50 */
    FLASH_START + 0x33ffff, /* Sector 51 */
    FLASH_START + 0x34ffff, /* Sector 52 */
    FLASH_START + 0x35ffff, /* Sector 53 */
    FLASH_START + 0x36ffff, /* Sector 54 */
    FLASH_START + 0x37ffff, /* Sector 55 */
    FLASH_START + 0x38ffff, /* Sector 56 */
    FLASH_START + 0x39ffff, /* Sector 57 */
    FLASH_START + 0x3affff, /* Sector 58 */
    FLASH_START + 0x3bffff, /* Sector 59 */
    FLASH_START + 0x3cffff, /* Sector 60 */
    FLASH_START + 0x3dffff, /* Sector 61 */
    FLASH_START + 0x3effff, /* Sector 62 */
    FLASH_START + 0x3fffff, /* Sector 63 */
};
char erasetable[FLASH_SECTORS];

/* Set and get the flash base address
 */
void SetFlashBase(unsigned long val)
{
	flashbaseov = (volatile u8 *)val;
}

volatile u8 *GetFlashBase(void)
{
	return flashbaseov != (volatile u8 *)0xffffffffL ?
	                      flashbaseov :
	                      (volatile u8 *)FLASH_START;
}

/* Set and get the flash size
 */
void SetFlashSize(unsigned long val)
{
	flashsizeov = val;
}

unsigned long GetFlashSize(void)
{
	return flashsizeov != 0xffffffffL ? flashsizeov : FLASH_SIZE;
}

void InitFlash(void)
{
    int i;
	flashstart = GetFlashBase();
	flashnext = flashstart;
    
    /* Mark all sectors as unerased */
    for (i = 0; i < FLASH_SECTORS; i++)
        erasetable[i] = 0;
}

void SetFlashAddr(u8 *addr)
{
	flashstart = (volatile u8 *)addr;
	flashnext = flashstart;
}


volatile u8 *GetNextFlashAddr(void)
{
	return flashnext;
}

/* Erase a segment of Flash memory */
void flash_erase(u32 start, u32 length)
{
    int i;
    unsigned long sector_base, phys_base, end;
    
    /* Calculate extents of range to erase */
    end = start + length - 1;
    
    /* Walk through each sector, erase any sectors within range */
    sector_base = FLASH_START;
    for (i = 0; i < FLASH_SECTORS; i++)
    {
        if (!erasetable[i] && (start <= sector_end[i]) && (end >= sector_base))
        {
            /* Start sector erase sequence */
            phys_base = (sector_base & 0x00070000) + FLASH_START;
            *FLASH_PAGE = (sector_base & 0x380000) >> 19;
            *(volatile char *)FLASH_START = (char)FLASH_KEY1;
            *(volatile char *)FLASH_START = (char)FLASH_KEY2;
            *(volatile char *)FLASH_START = (char)FLASH_KEY4;

            *(volatile char *)FLASH_START = (char)FLASH_KEY1;
            *(volatile char *)FLASH_START = (char)FLASH_KEY2;
            *(volatile char *)(phys_base) = (char)FLASH_KEY6;
            
            /* Wait until erase is done */
	        while(GetFlashVal(sector_base) != 0xff);

            /* Put the Flash in normal mode */
            *(volatile char *)phys_base = (char)0xf0;
            
            /* Mark sector as erased */
            erasetable[i] = 1;               
        }
        
        /* Advance to next sector */
        sector_base = sector_end[i] + 1;
    }
}

/* Burns flash data, starting at flashnext.
 * This embodies the burning algorithm for the
 * AMD29LV033C flash memory used on DM642 EVM
 */
void BurnFlash(u8 *data, u16 nBytes)
{
	u16 timeout;
	u8 c;
	volatile u8 *pdata;

    /* Put the Flash in normal mode */    
    *(volatile char *)FLASH_START = (char)0xf0;

    flash_erase((u32)flashnext, (u32)nBytes);
	while(nBytes--)		
	{
		/* Prep AMD
		 * 32MBit (4M x 8) Flash Memory
		 * for writing a byte.
		 */
		*FLASH_PAGE = (u8)(((u32)flashnext & 0x380000) >> 19);
		*(volatile char *)FLASH_START = (char)FLASH_KEY1;
		*(volatile char *)FLASH_START = (char)FLASH_KEY2;
		*(volatile char *)FLASH_START = (char)FLASH_KEY3;

        pdata = (volatile u8 *)((u32)flashnext & 0xffc7ffff);
		*pdata = *data;
		
		/* Spin here 'til programming completes
		 */
		c = *data++;
		timeout = 0;
		do timeout += 1;
		while(*pdata != c && timeout < (u16)0xffff);		
		flashnext++;
	}
	
    /* Put the Flash in normal mode */    
    *(volatile char *)FLASH_START = (char)0xf0;
}


/* The Flash Erase function uses
 * the AMD algorithm to erase the
 * entire chip.
 */

void EraseFlash(void)
{
    int i;
			
	/* Code to erase AMD29LV033C
	 * 32MBit (4MK X 8) Flash Memory
	 */
	*FLASH_PAGE = 0;
	*(volatile char *)FLASH_START = (char)FLASH_KEY1;
	*(volatile char *)FLASH_START = (char)FLASH_KEY2;
	*(volatile char *)FLASH_START = (char)FLASH_KEY4;

	*(volatile char *)FLASH_START = (char)FLASH_KEY1;
	*(volatile char *)FLASH_START = (char)FLASH_KEY2;
	*(volatile char *)FLASH_START = (char)FLASH_KEY5;

    /* Wait until erase is done */
	while(GetFlashVal(FLASH_START) != 0xff);

    /* Put the Flash in normal mode */    
    *(volatile char *)FLASH_START = (char)0xf0;

    /* Mark all sectors as erased */
    for (i = 0; i < FLASH_SECTORS; i++)
        erasetable[i] = 1;
    
	return;
}

void CKSSet(u16 val)
{
	cksum = val;
}
	
u16 CKSGet(void)
{
	return (u16)cksum;
}
		
u16 CKSAccumBuf(unsigned char *buf, unsigned int len)
{
    unsigned long src;
   
    src = (unsigned long)buf;
	while(len-- > 0)
	{
		cksum += GetFlashVal(src++);
		if(cksum > (unsigned long)0x0000ffff)
		{
			cksum += 1;
			cksum &= (unsigned long)0x0000ffff;
		} 
	}
	
	return (u16)cksum;
}

u8 GetFlashVal(unsigned long addr)
{
	*FLASH_PAGE = (u8)(((u32)addr & 0x380000) >> 19);
	return *(volatile u8 *)(addr & 0xffc7ffff);
}

void SendFlashBufToHost(u16 cmd, unsigned long addr, u16 bytecount)
{
    u8 *pflash = (u8 *)addr;
    u16 n = bytecount > 256 ? 256 : bytecount;

	StoreCmd(cmd);     
	StoreArg(0, bytecount);	
    
	GetFlashBuf(GetData(), pflash, n);
}

static GetFlashBuf(u8 *dest, u8 *flashsrc, u16 nBytes)
{
    unsigned long src, dst, i;

    src = (unsigned long)flashsrc;
    dst = (unsigned long)dest;
    
    for (i = 0; i < nBytes; i++)
    {
        *((u8 *)dst++) = GetFlashVal(src++);
    }
}
